/**
 * 
 */
package src.model.gameObject.ability;

import src.model.gameObject.GameObject;
import src.model.gameObject.eventBrokers.MoveEventBroker;
import src.model.gameObject.eventInterfaces.MovePositionListener;
import src.model.gameObject.eventInterfaces.MovePublisher;
import src.model.gameWorld.LookupTable;
import src.model.gameWorld.Position;
import src.model.gameWorld.ActualMap;

/**
 * <b>Overview</b><br>
 * <p>This area effect teleports a GameObject that moves onto this to a random
 * position on the map (legal positions only)</p>
 * <br><br>
 * <b>Responsibilites</b><br>
 * <p>Teleport anything that moves onto it.</p>
 * <br><br>
 * <b>Collaborators</b>
 * <br>
 * ActualMap - To move things around the map.
 * <br>
 * <b>Implementor</b> - Tristan Lohman<br>
 * <b>Tester</b> - Bruce<br>
 * @author Tristan
 *
 */
public class AETeleport extends Ability implements MovePositionListener, MovePublisher {
	private ActualMap am;
	/**
	 * Constructs a new area effect and registers it with any appropriate brokers.
	 * @param go The GameObject that owns this.
	 * @param am The ActualMap which this resides on.
	 * @param lookup The LookupTable for this Area Effect.
	 */
	public AETeleport(GameObject go, ActualMap am, LookupTable lookup) {
		super(go, AbilityType.AETELEPORT,  lookup);
		MoveEventBroker.register(am.findObject(super.gameObject()), this);
		MoveEventBroker.register(super.gameObject(), this);
		this.am = am;
	}
	
	/**
	 * Upon notification that something moved onto this, the area effect calculates a random position and
	 * tries to move it. If it was successful, publishes the move event. If not, it calculates a new position and tries
	 * until a successful move is made.
	 * @param go The GameObject that moved onto this area effect.
	 */
	public void notifyPositionMovedOnto(GameObject go){
		int newX = (int)(Math.random() * Position.getXBoundary());
		int newY = (int)(Math.random() * Position.getYBoundary());
		Position moveTo = new Position(newX, newY);
		if(am.moveObject(go, moveTo)) publishMove(go, moveTo);
		else notifyPositionMovedOnto(go);
	}
	
	/**
	 * Notifies this when its PlayerGameObject has moved, allowing it to notify the MoveEventBroker
	 * to change its location that it listens for. This allows us to have area effects that move.<br>
	 * NOTE: Better design to have MoveEventBroker handle this.
	 * @param p The Position that this Ability's Owner moved to.
	 */
	public void notifyGameObjectMoved(Position p){
		MoveEventBroker.remapListener(this, p);
	}

	public void destroySub(){
		this.am = null;
		MoveEventBroker.unregister(am.findObject(super.gameObject()), this);
		MoveEventBroker.unregister(super.gameObject(), this);
	}
	
	public void publishMove(GameObject go, Position p){
		MoveEventBroker.recognizeMove(go, p);
	}
}
